'use strict';


let pc;
let clientID = "";
let remoteID = "";
let myDataChannel;

let receivedBuffer = [];
let receivedSize = 0;

const uiFileInput = document.querySelector('input#fileInput');
const uiSendFile = document.getElementById('sendFile');
const downloadAnchor = document.getElementById('download');

let uiID, btnStart, uiRID, uiPcState;


const t = {
    Offer: "offer",
    Answer: "answer",
    Candidate: "candidate",
    NoRemoteID: "no-remote-id"
}

const signaling = new Signaling(`ws://${window.location.hostname}:8082/signaling`, onMessage);

signaling.start();

function onMessage(event) {
  const { Type, To, From, Data } = JSON.parse(event.data);
  console.info(`Type: ${Type}, To: ${To}, From: ${From}, Data: ${JSON.stringify(Data)}`);

  switch (Type.toLowerCase()) {
    case "register":
      onRegister(Data);
      break;
    case t.Answer:
      onAnswer(Data);
      break;
    case t.Offer:
      onOffer(From, Data);
      break;
    case t.Candidate:
        onCandidate(Data);
        break;
    case t.NoRemoteID:
        onNoRemoteID();
        break;
    default:
        console.info(`no handling [Type: ${Type}, To: ${To}, From: ${From}, Data: ${Data}]`);
  }
}

async function onNoRemoteID() {
    alert(`the remote id doesn't exist.`)
}

async function onCandidate(data) {
    if (data) {
        await pc.addIceCandidate(data);
    } else {
        console.info("data empty:", data)
        await pc.addIceCandidate(null)
    }
}

async function onAnswer(data) {
    if (!pc) {
        console.error("no peerconnection")
    }
    const remoteDesc = new RTCSessionDescription(data);
    await pc.setRemoteDescription(remoteDesc);
}

async function onRegister({ID}) {
    const uiID = document.getElementById("clientID")
    uiID.innerText = ID;
    clientID = ID;
}

async function onOffer(From, data) {
    if (pc) {
        console.error('existing peerconnection');
        return;
    }

    remoteID = From;
    await createConnection();
    await pc.setRemoteDescription(new RTCSessionDescription(data))
    
    const answer = await pc.createAnswer();
    await pc.setLocalDescription(answer);
    signaling.sendMessage(remoteID, t.Answer, answer)
}

function createConnection() {
    const configuration = {'iceServers': [
       // { urls: 'stun:stun.l.google.com:19302'},
        { urls: 'stun:192.168.1.24:3478'}
    ]}
    pc = new RTCPeerConnection();
    pc.addEventListener( 'icecandidate', e => {
        if (e.candidate) {
            console.info("send: ", e.candidate)
            signaling.sendMessage(remoteID, t.Candidate, e.candidate)
        }
    });

    pc.addEventListener('icecandidateerror', (event) => {console.error(event) });


    pc.addEventListener('connectionstatechange', event => {
        uiPcState.innerText = pc.connectionState;
        if (pc.connectionState === 'connected') {
        } 
    });

    pc.addEventListener('datachannel', ev => {
        console.info('dataChannel: ', ev);
        myDataChannel = ev.channel;
        initMyDataChannelEvent();
    })
}

async function makeCall() {
    if (!uiRID.value) {
        alert("please input remote ID");
        return
    }

    remoteID = uiRID.value;
    await createConnection();

    myDataChannel = pc.createDataChannel("myDataChannel");
    initMyDataChannelEvent();

    const offer = await pc.createOffer();
    await pc.setLocalDescription(offer);
    signaling.sendMessage(remoteID, t.Offer, offer)

}

function initMyDataChannelEvent() {
    myDataChannel.addEventListener('open', ev => {console.info("dc open: ", ev)});
    myDataChannel.addEventListener('close', ev => {console.info("dc close: ", ev)});
    myDataChannel.addEventListener('closing', ev => {console.info("dc closing: ", ev)});
    myDataChannel.addEventListener('error', ev => {console.info("dc error: ", ev)});
    myDataChannel.addEventListener('message', onReceiveMessageCallback);
}

let filename = '';
let filesize = 0;

function onReceiveMessageCallback(event) {
    if (filename === '') {
        console.info('file info: ', event);

        const fileInfo = JSON.parse(event.data);
        filename = fileInfo.name;
        filesize = fileInfo.size;
        console.info(`fileInfo : ${fileInfo}, filename: ${filename}`)
        return
    }

    receivedBuffer.push(event.data);
    receivedSize += event.data.byteLength;
    console.info("o receive message:", event.data.byteLength);

    if (receivedSize === filesize) {
        console.info("receiving complated")
        const received = new Blob(receivedBuffer);
        receivedBuffer = [];

        downloadAnchor.href = URL.createObjectURL(received);
        downloadAnchor.download = filename;
        downloadAnchor.textContent = `Click to download "${filename}" (${filesize} bytes)`;
        downloadAnchor.style.display = 'block';

        //filename = '';
        //filesize  = 0;
    }
    
}

function sendFile() {
    if (uiFileInput.files.length === 0) {
        alert('please choose a file.');
        return;
    }

    const file = uiFileInput.files[0];
    console.log(`File is ${[file.name, file.size, file.type, file.lastModified].join(' ')}`);

    if (file.size === 0) {
        alert('the file size is zero');
        return;
    }

    const fileInfo = {name: file.name, size: file.size};
    // const blobFileInfo = new Blob([JSON.stringify(fileInfo)], {type: 'application/json'})
    myDataChannel.send(JSON.stringify(fileInfo));
    
    const chunkSize = 16384;
    let fileReader = new FileReader();
    let offset = 0;
    fileReader.addEventListener('error', error => console.error("Error reading file: ", error));
    fileReader.addEventListener('abort', event => console.log('File reading aborted:', event));
    fileReader.addEventListener('load', e => {
        myDataChannel.send(e.target.result);
        offset += e.target.result.byteLength;
        if (offset < file.size) {
            readSlice(offset);
        }
    });

    const readSlice = (o) => {
        const slice = file.slice(offset, o + chunkSize); 
        fileReader.readAsArrayBuffer(slice);
    }

    readSlice(0);
}

document.addEventListener("DOMContentLoaded", () => {
    uiPcState = document.getElementById("pc-state")
    uiRID = document.getElementById("remoteID");
    btnStart = document.getElementById("start");
    btnStart.addEventListener("click", makeCall);

    uiSendFile.addEventListener('click', sendFile);
})